package com.ruoyi.mp.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileTypeUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.ai.service.url.DomainService;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.file.FileUploadUtils;
import com.ruoyi.mp.convert.MpMaterialConvert;
import com.ruoyi.mp.domain.MpMaterial;
import com.ruoyi.mp.domain.bo.MpMaterialBo;
import com.ruoyi.mp.domain.vo.MpMaterialVo;
import com.ruoyi.mp.domain.vo.material.MpMaterialUploadNewsImageReqVO;
import com.ruoyi.mp.domain.vo.material.MpMaterialUploadPermanentReqVO;
import com.ruoyi.mp.domain.vo.material.MpMaterialUploadTemporaryReqVO;
import com.ruoyi.mp.mapper.MpMaterialMapper;
import com.ruoyi.mp.service.IMpMaterialService;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.material.WxMpMaterialUploadResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.util.*;

/**
 * 素材管理Service业务层处理
 *
 * @author yh
 * @date 2024-01-26
 */
@Service
@Slf4j
public class MpMaterialServiceImpl implements IMpMaterialService {
    @Autowired
    private MpMaterialMapper mpMaterialMapper;

    @Autowired
    private WxMpService wxMpService;

    @Autowired
    private DomainService domainService;


    /**
     * 查询公众号素材列表
     */
    @Override
    public TableDataInfo<MpMaterialVo> queryPageList(MpMaterialBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<MpMaterial> lqw = buildQueryWrapper(bo);
        Page<MpMaterialVo> result = mpMaterialMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询公众号素材列表
     */
    @Override
    public List<MpMaterialVo> queryList(MpMaterialBo bo) {
        LambdaQueryWrapper<MpMaterial> lqw = buildQueryWrapper(bo);
        return mpMaterialMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<MpMaterial> buildQueryWrapper(MpMaterialBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<MpMaterial> lqw = Wrappers.lambdaQuery();
        lqw.eq(StringUtils.isNotBlank(bo.getMediaId()), MpMaterial::getMediaId, bo.getMediaId());
        lqw.eq(StringUtils.isNotBlank(bo.getType()), MpMaterial::getType, bo.getType());
        lqw.eq(bo.getPermanent() != null, MpMaterial::getPermanent, bo.getPermanent());
        lqw.like(StringUtils.isNotBlank(bo.getName()), MpMaterial::getName, bo.getName());
        return lqw;
    }

    /**
     * 删除素材管理信息
     *
     * @param id 素材管理主键
     * @return 结果
     */
    @Override
    public int deleteMpMaterialById(Long id) {
        MpMaterial material = mpMaterialMapper.selectById(id);
        if (material == null) {
            throw new ServiceException("素材找不到");
        }

        // 第一步，从公众号删除
        if (Objects.equals(material.getPermanent(),1)) {
            try {
                wxMpService.getMaterialService().materialDelete(material.getMediaId());
            } catch (WxErrorException e) {
                throw new ServiceException("素材删除异常");
            }
        }

        // 第二步，从数据库中删除
        return mpMaterialMapper.deleteById(id);
    }

    @Override
    public MpMaterial uploadTemporaryMaterial(MpMaterialUploadTemporaryReqVO reqVO) throws IOException {
        // 第一步，上传到公众号
        File file = null;
        WxMediaUploadResult result;
        String mediaId;
        String url;
        try {
            // 写入到临时文件
            file = FileUtil.touch(RuoYiConfig.getUploadPath() + "/" + reqVO.getFile().getOriginalFilename());
            reqVO.getFile().transferTo(file);
            // 上传到公众号
            result = wxMpService.getMaterialService().mediaUpload(reqVO.getType(), file);
            // 上传到文件服务
            mediaId = ObjUtil.defaultIfNull(result.getMediaId(), result.getThumbMediaId());
            url = uploadFile(mediaId, file);
        } catch (WxErrorException e) {
            log.error("[uploadTemporaryMaterial][上传文件({}) 到公众号失败]", file, e);
            throw new ServiceException("素材上传失败");
        } finally {
            FileUtil.del(file);
        }

        // 第二步，存储到数据库
        MpMaterial material = MpMaterialConvert.convert(mediaId, reqVO.getType(), url,
            reqVO.getFile().getName());
        material.setPermanent(0);
        mpMaterialMapper.insert(material);
        return material;
    }

    @Override
    public MpMaterial uploadPermanentMaterial(MpMaterialUploadPermanentReqVO reqVO) throws IOException {
        // 第一步，上传到公众号
        String name = StrUtil.blankToDefault(reqVO.getName(), reqVO.getFile().getOriginalFilename());
        File file = null;
        WxMpMaterialUploadResult result;
        String mediaId;
        String url;
        try {
            // 写入到临时文件
            file = FileUtil.touch(RuoYiConfig.getUploadPath() + "/" + reqVO.getFile().getOriginalFilename());
            reqVO.getFile().transferTo(file);
            // 上传到公众号
            result = wxMpService.getMaterialService().materialFileUpload(reqVO.getType(),
                MpMaterialConvert.convert(name, file, reqVO.getTitle(), reqVO.getIntroduction()));
            // 上传到文件服务
            mediaId = ObjUtil.defaultIfNull(result.getMediaId(), result.getMediaId());
            url = uploadFile(mediaId, file);
        } catch (WxErrorException e) {
            log.error("[uploadTemporaryMaterial][上传文件({}) 到公众号失败]", file, e);
            throw new ServiceException("素材上传失败");
        } finally {
            FileUtil.del(file);
        }

        // 第二步，存储到数据库
        MpMaterial material = MpMaterialConvert.convert(mediaId, reqVO.getType(), url,
            name, reqVO.getTitle(), reqVO.getIntroduction(), result.getUrl());
        material.setPermanent(1);
        mpMaterialMapper.insert(material);
        return material;
    }

    @Override
    public String uploadNewsImage(MpMaterialUploadNewsImageReqVO reqVO) throws IOException {
        File file = null;
        try {
            // 写入到临时文件
            file = FileUtil.touch(RuoYiConfig.getUploadPath() + "/" + reqVO.getFile().getOriginalFilename());
            reqVO.getFile().transferTo(file);
            // 上传到公众号
            return wxMpService.getMaterialService().mediaImgUpload(file).getUrl();
        } catch (WxErrorException e) {
            log.error("[uploadNewsImage][上传文件({}) 到公众号失败]", file, e);
            throw new ServiceException("素材上传失败");
        } finally {
            FileUtil.del(file);
        }
    }

    @Override
    public List<MpMaterial> getMaterialListByMediaId(Collection<String> mediaIds) {
        if (CollUtil.isEmpty(mediaIds)) {
            return Collections.emptyList();
        }
        LambdaQueryWrapper<MpMaterial> lqw = Wrappers.lambdaQuery();
        lqw.in( MpMaterial::getMediaId, mediaIds);
        return mpMaterialMapper.selectList(lqw);
    }

    private String uploadFile(String mediaId, File file) {
        // 上传文件路径
        String filePath = RuoYiConfig.getUploadPath();
        String fileName = mediaId + "." + FileTypeUtil.getType(file);
        String fullFilePath = filePath + "/" + fileName;
        // 上传并返回新文件名称
        String url;
        try {
            FileUtil.writeBytes(FileUtil.readBytes(file), fullFilePath);
            url = FileUploadUtils.getPathFileName(filePath, fileName);
        } catch (IORuntimeException | IOException e) {
            log.error("上传媒体文件异常", e);
            throw new ServiceException(e.getMessage());
        }
        return domainService.getUrl() + url;
    }
}
